跳到主要内容

结构模式-组合模式

组合模式是什么?

组合模式:将对象组合成树形结构表示:“部分-整体” 的层次结构(组合模式使得用户对单个对象和组合对象的使用具有一致性)

classDiagram Client --> Component Component <|-- Leaf Component <|-- Composite Composite o--> Component Component: +add(Component) Component: +remove(Component) Component: +display() Composite: +add(Component) Composite: +remove(Component) Composite: +display() Leaf: +display()

说白了,就是用来存储树型结构的数据的模式

graph TD aComposite --> aLeaf aComposite --> bLeaf aComposite --> bComposite aComposite --> cLeaf bComposite --> cComposite bComposite --> dLeaf cComposite --> eLeaf cComposite --> fLeaf cComposite --> gLeaf

Golang 的组合

Golang 其实与 Java 的继承有很多不同,并不能简单的理解为继承、多态、重写这几个功能的不同实现方式,实际上,Golang 是提倡共用组合与接口,如下代码所示:

package main

import (
"fmt"
)

// 注意,这里定义了一个接口
type IHello interface {
Hello(name string)
}

type A struct {
}

func (*A) Hello(name string) {
fmt.Println("hello " + name + ", i am a")
}

type D struct {
}

func (*D) Hello(name string) {
fmt.Println("hello " + name + ", i am d")
}

type B struct {
IHello
}

func (*B) Hello(name string) {
fmt.Println("hello " + name + ", i am b")
}

type C struct {
IHello
}

func main() {
name := "Lee"
a := A{}
a.Hello(name) //hello Lee, i am a

b := B{&A{}}
b.Hello(name) //hello Lee, i am b

b.IHello.Hello(name) //hello Lee, i am a

c := C{&A{}}
c.Hello(name) //hello Lee, i am a

c.IHello = &D{}
c.Hello(name) //hello Lee, i am d
}
  • A 的指针继承了接口 IHello
  • B,C 中嵌入了接口 IHello,
  • B C两者在赋值时,同时可以根据运行时上下文指定其他具体实现,比如D,更加灵活。

golang从语言级别对组合做了充分的语法糖,使得组合更加高效。我来看一段 java 的组合实现

public interface IHello {
public void hello();
}

public class A implements IHello {
@Override
public void hello() {
System.out.println("Hello, I am A.");
}
}

public class B implements IHello {
@Override
public void hello() {
System.out.println("Hello, I am B.");
}
}

public class C {
IHello h;
public void hello() {
h.hello();
}
}

public static void main(String args[]) {
C c = new C();
c.h = new A();
c.hello();
c.h = new B();
c.hello();
}

例中类 C 组合了接口 IHello, 如需暴露 IHello 的方法则需要添加一个代理方法

public void hello() {
h.hello();
}

这样在代码量上会多于继承方式。golang 中无需额外代码即可提供支持。

References

如何理解go语言提倡组合,不提倡继承